#!/usr/bin/env python

import argparse
import contextlib
import errno
import fnmatch
import glob
import os
import re
import shutil
import subprocess
import sys
import zipfile

from lib.config import get_output_dir


SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
VENDOR_DIR = os.path.join(SOURCE_ROOT, 'vendor')
DIST_DIR = os.path.join(SOURCE_ROOT, 'dist')
SRC_DIR = os.path.join(SOURCE_ROOT, 'src')

# Almost everything goes into the main zip file...
MAIN_DIR = os.path.join(DIST_DIR, 'main')
DIST_SRC_DIR = os.path.join(MAIN_DIR, 'src')

TARGET_PLATFORM = {
  'cygwin': 'win32',
  'darwin': 'darwin',
  'linux2': 'linux',
  'win32': 'win32',
}[sys.platform]

SHARED_LIBRARY_SUFFIX = {
  'darwin': 'dylib',
  'linux': 'so',
  'win32': 'dll',
}[TARGET_PLATFORM]
STATIC_LIBRARY_SUFFIX = {
  'darwin': 'a',
  'linux': 'a',
  'win32': 'lib',
}[TARGET_PLATFORM]

COMPONENTS = ['static_library', 'shared_library']
BINARIES = {
  'all': [
    'content_shell.pak',
    'icudtl.dat',
    'natives_blob.bin',
    'snapshot_blob.bin',
    os.path.join('gen', 'blink', 'public', 'resources', 'blink_image_resources_200_percent.pak'),
    os.path.join('gen', 'content', 'app', 'resources', 'content_resources_200_percent.pak'),
    os.path.join('gen', 'ui', 'resources', 'ui_resources_200_percent.pak'),
    os.path.join('gen', 'ui', 'resources', 'ui_resources_300_percent.pak'),
    os.path.join('gen', 'ui', 'views', 'resources', 'views_resources_200_percent.pak'),
    os.path.join('gen', 'ui', 'views', 'resources', 'views_resources_300_percent.pak'),
  ],
  'darwin': [
    'libffmpeg.dylib',
  ],
  'linux': [
    'libffmpeg.so',
  ],
  'win32': [
    'd3dcompiler_47.dll',
    'ffmpeg.dll',
    'ffmpeg.dll.lib',
    'libEGL.dll',
    'libGLESv2.dll',
    os.path.join('gen', 'ui', 'resources', 'ui_unscaled_resources.rc'),
  ],
}

BINARIES_SHARED_LIBRARY = {
  'darwin': [
    os.path.join('obj', 'components', 'cdm', 'renderer', 'librenderer.a'),
    os.path.join('obj', 'net', 'libhttp_server.a'),
    os.path.join('obj', 'third_party', 'webrtc', 'base', 'librtc_base.a'),
    os.path.join('obj', 'third_party', 'webrtc', 'base', 'librtc_base_approved.a'),
    os.path.join('obj', 'ui', 'events', 'libdom_keycode_converter.a'),
    os.path.join('obj', 'pdf', 'libpdf.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libpdfium.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfdrm.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libformfiller.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfpdfapi.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfpdfdoc.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfpdftext.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfxcodec.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfxcrt.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfxedit.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfxge.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfxjs.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libjavascript.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libpdfwindow.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'third_party', 'libfx_freetype.a'),
  ],
  'linux': [
    os.path.join('obj', 'components', 'cdm', 'renderer', 'librenderer.a'),
    os.path.join('obj', 'net', 'libhttp_server.a'),
    os.path.join('obj', 'third_party', 'webrtc', 'base', 'librtc_base.a'),
    os.path.join('obj', 'third_party', 'webrtc', 'base', 'librtc_base_approved.a'),
    os.path.join('obj', 'ui', 'events', 'libdom_keycode_converter.a'),
    os.path.join('obj', 'pdf', 'libpdf.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libpdfium.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfdrm.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libformfiller.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfpdfapi.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfpdfdoc.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfpdftext.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfxcodec.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfxcrt.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfxedit.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfxge.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libfxjs.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libjavascript.a'),
    os.path.join('obj', 'third_party', 'pdfium', 'libpdfwindow.a'),
  ],
  'win32': [
    os.path.join('obj', 'base', 'base_static_cc.pdb'),
    os.path.join('obj', 'base', 'base_static.lib'),
    os.path.join('obj', 'components', 'cdm', 'renderer', 'renderer_cc.pdb'),
    os.path.join('obj', 'components', 'cdm', 'renderer', 'renderer.lib'),
    os.path.join('obj', 'net', 'http_server_cc.pdb'),
    os.path.join('obj', 'net', 'http_server.lib'),
    os.path.join('obj', 'pdf', 'pdf_cc.pdb'),
    os.path.join('obj', 'pdf', 'pdf.lib'),
    os.path.join('obj', 'sandbox', 'win', 'sandbox_cc.pdb'),
    os.path.join('obj', 'sandbox', 'win', 'sandbox.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'pdfium_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'pdfium.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'fdrm_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'fdrm.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'formfiller_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'formfiller.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'fpdfapi_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'fpdfapi.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'fpdfdoc_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'fpdfdoc.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'fpdftext_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'fpdftext.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'fxcodec_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'fxcodec.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'fxcrt_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'fxcrt.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'fxedit_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'fxedit.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'fxge_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'fxge.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'fxjs_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'fxjs.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'javascript_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'javascript.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'pdfwindow_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'pdfwindow.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'third_party', 'bigint_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'third_party', 'fx_agg_cc.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'third_party', 'fx_freetype_c.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'third_party', 'fx_freetype.lib'),
    os.path.join('obj', 'third_party', 'pdfium', 'third_party', 'fx_lcms2_c.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'third_party', 'fx_libopenjpeg_c.pdb'),
    os.path.join('obj', 'third_party', 'pdfium', 'third_party', 'fx_zlib_c.pdb'),
    os.path.join('obj', 'third_party', 'webrtc', 'base', 'rtc_base_cc.pdb'),
    os.path.join('obj', 'third_party', 'webrtc', 'base', 'rtc_base.lib'),
    os.path.join('obj', 'third_party', 'webrtc', 'base', 'rtc_base_approved_cc.pdb'),
    os.path.join('obj', 'third_party', 'webrtc', 'base', 'rtc_base_approved.lib'),
    os.path.join('obj', 'ui', 'events', 'dom_keycode_converter_cc.pdb'),
    os.path.join('obj', 'ui', 'events', 'dom_keycode_converter.lib'),
    # PDB files for libraries that generated under obj/chromiumcontent:
    os.path.join('obj', 'components', 'security_state', 'core', 'core_cc.pdb'),
    os.path.join('obj', 'components', 'security_state', 'content', 'content_cc.pdb'),
    os.path.join('obj', 'content', 'sandbox_helper_win_cc.pdb'),
    os.path.join('obj', 'ppapi', 'cpp', 'objects_cc.pdb'),
    os.path.join('obj', 'ppapi', 'cpp', 'private', 'internal_module_cc.pdb'),
    os.path.join('obj', 'third_party', 'libjpeg_turbo', 'libjpeg_c.pdb'),
    os.path.join('obj', 'third_party', 'libjpeg_turbo', 'simd_c.pdb'),
    os.path.join('obj', 'third_party', 'libyuv', 'libyuv_internal_cc.pdb'),
    os.path.join('obj', 'third_party', 'webrtc', 'modules', 'desktop_capture', 'desktop_capture_cc.pdb'),
    os.path.join('obj', 'third_party', 'webrtc', 'modules', 'desktop_capture', 'desktop_capture_differ_sse2_cc.pdb'),
    os.path.join('obj', 'third_party', 'webrtc', 'modules', 'desktop_capture', 'primitives_cc.pdb'),
    os.path.join('obj', 'third_party', 'webrtc', 'system_wrappers', 'system_wrappers_cc.pdb'),
  ],
}

ARCH_BLACKLIST = {
  'arm': [
    'libdesktop_capture_differ_sse2.a',
  ],
  'arm64': [
    'libdesktop_capture_differ_sse2.a',
  ],
  'x64': [
    'libprotobuf_full_do_not_use.a',
    'libprotoc_lib.a',
    'libyuv_internal_cc.pdb',
  ],
  'ia32': [
  ],
}

SYMBOLS = {
  'darwin': [
    # OS X has a more complicated symbol creation process. See
    # create_dsym() and copy_symbols().
  ],
  'linux': [
    'libosmesa.so.dbg',
  ],
  'win32': [
    'libGLESv2.dll.pdb',
  ],
}

# Emperically determined to be required by client apps.
INCLUDE_DIRS = [
  'base',
  'build',
  'cc',
  'chrome/browser/ui/libgtkui',
  'components/cdm',
  'components/component_updater',
  'components/cookie_config',
  'components/display_compositor',
  'components/os_crypt',
  'components/prefs',
  'components/security_state',
  'components/update_client',
  'content/browser',
  'content/common',
  'content/public',
  'content/renderer',
  'crypto',
  'device',
  'ipc',
  'gin',
  'gpu',
  'media',
  'mojo',
  'net',
  'pdf',
  'printing',
  'ppapi',
  'sandbox',
  'services',
  'skia',
  'storage',
  'testing',
  'third_party/boringssl',
  'third_party/khronos',
  'third_party/WebKit/Source/platform',
  'third_party/WebKit/Source/wtf',
  'third_party/WebKit/public',
  'third_party/libyuv/include',
  'third_party/webrtc',
  'third_party/icu/source',
  'third_party/mojo/src/mojo/public',
  'third_party/skia',
  'third_party/widevine',
  'third_party/wtl/include',
  'ui',
  'url',
  'v8/include',
  'webkit',
] + {
  'darwin': [],
  'linux': [
    'dbus',
    'third_party/speech-dispatcher',
  ],
  'win32': [],
}[TARGET_PLATFORM]
GENERATED_INCLUDE_DIRS = [
  'base',
  'cc',
  'content',
  'gpu',
  'ipc',
  'mojo',
  'media',
  'net',
  'ppapi',
  'printing',
  'third_party/WebKit',
  'ui',
  'url',
  'services',
  'skia',
]
OTHER_HEADERS = [
  'content/common/content_export.h',
  'ui/events/keycodes/dom/dom_key_data.inc',
  'ui/events/keycodes/dom/keycode_converter_data.inc',
]
OTHER_SOURCES = [
]
OTHER_DIRS = [
  os.path.join('ui', 'resources', 'cursors'),
]


def main():
  args = parse_args()
  target_arch = args.target_arch
  create_debug_archive = args.create_debug_archive

  if create_debug_archive:
    check_create_debug_archive(target_arch)

  # Some libraries are not available for certain arch.
  for lib in ARCH_BLACKLIST[target_arch]:
    if lib in BINARIES[TARGET_PLATFORM]:
      BINARIES[TARGET_PLATFORM].remove(lib)

  rm_rf(DIST_DIR)
  os.makedirs(DIST_DIR)

  for component in COMPONENTS:
    if args.component == 'all' or args.component == component:
      copy_binaries(target_arch, component, create_debug_archive)
      copy_generated_sources(target_arch, component)
      copy_locales(target_arch, component)

  copy_ffmpeg(target_arch)
  copy_sources()
  generate_licenses()
  if not args.no_zip:
    create_zip(create_debug_archive)


def parse_args():
  parser = argparse.ArgumentParser(description='Create distribution')
  parser.add_argument('-t', '--target_arch', default='x64', help='x64 or ia32')
  parser.add_argument('--create-debug-archive',
                      default=False,
                      required=False,
                      action='store_true',
                      help='Create archive with debug symbols and source code')
  parser.add_argument('-c', '--component', default='all',
                      help='static_library or shared_library or all')
  parser.add_argument('--no_zip', action='store_true',
                      help='Do not create zip distribution')
  return parser.parse_args()


def program_available(prog):
  try:
    subprocess.check_output([prog, '--help'])
    return True
  except OSError as e:
    return False


def check_create_debug_archive(target_arch):
  errmsg = '--create-debug-archive option requires missing program {0}'
  for prog in ['gdb', 'objcopy']:
    if target_arch == 'arm':
      prog = 'arm-linux-gnueabihf-' + prog
    elif target_arch == 'arm64':
      prog = 'aarch64-linux-gnu-' + prog
    if not program_available(prog):
      print errmsg.format(prog)
      sys.exit(1)


def copy_with_blacklist(target_arch, src, dest):
  if os.path.basename(src) in ARCH_BLACKLIST[target_arch]:
    return
  shutil.copy2(src, dest)


def copy_binaries(target_arch, component, create_debug_archive):
  output_dir = get_output_dir(SOURCE_ROOT, target_arch, component)
  target_dir = os.path.join(MAIN_DIR, component)
  mkdir_p(target_dir)

  binaries = BINARIES['all'] + BINARIES[TARGET_PLATFORM]
  if component == 'shared_library':
    binaries += BINARIES_SHARED_LIBRARY[TARGET_PLATFORM]
  for binary in binaries:
    copy_with_blacklist(target_arch, os.path.join(output_dir, binary), target_dir)

  # Copy all static libraries from chromiumcontent
  for library in glob.glob(os.path.join(output_dir, 'obj', 'chromiumcontent', '*.' + STATIC_LIBRARY_SUFFIX)):
    shutil.copy2(library, target_dir)

  if component == 'shared_library':
    match = '*.{0}'.format(SHARED_LIBRARY_SUFFIX)
  else:
    match = '*.{0}'.format(STATIC_LIBRARY_SUFFIX)

  if TARGET_PLATFORM == 'darwin':
    if component == 'shared_library':
      for library in glob.glob(os.path.join(output_dir, '*.dylib')):
        copy_with_blacklist(target_arch, library, target_dir)

  if TARGET_PLATFORM == 'win32':
    if component == 'shared_library':
      # out/Release/*.dll(.lib)
      for dll in glob.glob(os.path.join(output_dir, '*.dll')):
        lib = dll + '.lib'
        if os.path.exists(lib):
          copy_with_blacklist(target_arch, dll, target_dir)
          copy_with_blacklist(target_arch, lib, target_dir)
    elif component == 'static_library':
      # out/Release/*.pdb
      for root, _, filenames in os.walk(output_dir):
        for pdb in filenames:
          if pdb.endswith('.pdb'):
            shutil.copy2(os.path.join(root, pdb), target_dir)

  if TARGET_PLATFORM == 'linux':
    if component == 'shared_library':
      # out/Release/lib/*.so
      for library in glob.glob(os.path.join(output_dir, '*.so')):
        copy_with_blacklist(target_arch, library, target_dir)

  if TARGET_PLATFORM in ['linux', 'darwin']:
    if create_debug_archive:
      print 'Extracting debug symbols...'
    for binary in BINARIES[TARGET_PLATFORM]:
      run_strip(target_arch,
                os.path.join(target_dir, os.path.basename(binary)),
                create_debug_archive)
    if component == 'shared_library':
      for library in glob.glob(os.path.join(target_dir, match)):
        run_strip(target_arch, library, create_debug_archive)
      # move .debug files into a separate directory
      debug_dir = os.path.join(os.path.dirname(target_dir), '.debug')
      mkdir_p(debug_dir)
      for debug_file in glob.glob(os.path.join(target_dir, '*.debug')):
        shutil.move(debug_file, debug_dir)

  # Copy chromedriver and mksnapshot
  # Take them from the "ffmpeg" config, where they are built with all
  # dependencies statically linked.
  if component == 'static_library':
    if TARGET_PLATFORM == "win32":
      binaries = [ 'chromedriver.exe', 'mksnapshot.exe' ]
    elif target_arch == 'arm':
      binaries = [ 'chromedriver', 'clang_x86_v8_arm/mksnapshot' ]
    elif target_arch == 'arm64':
      binaries = [ 'chromedriver', 'clang_x64_v8_arm64/mksnapshot' ]
    else:
      binaries = [ 'chromedriver', 'mksnapshot' ]

    ffmpeg_output_dir = get_output_dir(SOURCE_ROOT, target_arch, 'ffmpeg')
    for binary in binaries:
      shutil.copy2(os.path.join(ffmpeg_output_dir, binary), target_dir)


def copy_generated_sources(target_arch, component):
  output_dir = get_output_dir(SOURCE_ROOT, target_arch, component)
  target_dir = os.path.join(MAIN_DIR, component)
  for include_path in GENERATED_INCLUDE_DIRS:
    copy_headers(include_path,
                 relative_to=os.path.join(output_dir, 'gen'),
                 destination=os.path.join(target_dir, 'gen'))

def copy_locales(target_arch, component):
  output_dir = get_output_dir(SOURCE_ROOT, target_arch, component)
  target_dir = os.path.join(MAIN_DIR, component, 'locales')
  mkdir_p(target_dir)
  src_dir = os.path.join(output_dir, 'gen', 'content', 'app', 'strings')
  for src_file in glob.glob(os.path.join(src_dir, 'content_strings_*.pak')):
    filename = os.path.basename(src_file)
    new_name = re.sub('content_strings_', '', filename)
    shutil.copy2(src_file, os.path.join(target_dir, new_name))

def copy_sources():
  for include_path in INCLUDE_DIRS:
    copy_headers(include_path, relative_to=SRC_DIR, destination=DIST_SRC_DIR)

  for path in OTHER_HEADERS + OTHER_SOURCES:
    copy_source_file(os.path.join(SRC_DIR, path), relative_to=SRC_DIR,
                     destination=DIST_SRC_DIR)

  for path in OTHER_DIRS:
    copy_dir(path, relative_to=SRC_DIR, destination=DIST_SRC_DIR)


def copy_ffmpeg(target_arch):
  output_dir = get_output_dir(SOURCE_ROOT, target_arch, 'ffmpeg')
  if TARGET_PLATFORM == 'darwin':
    binary = 'libffmpeg.dylib'
  elif TARGET_PLATFORM == 'linux':
    binary = 'libffmpeg.so'
  elif TARGET_PLATFORM == 'win32':
    binary = 'ffmpeg.dll'

  target_dir = os.path.join(MAIN_DIR, 'ffmpeg')
  mkdir_p(target_dir)
  shutil.copy2(os.path.join(output_dir, binary), target_dir)



def copy_headers(relative_path, relative_to, destination):
  abs_path = os.path.join(relative_to, relative_path)
  for dirpath, dirnames, filenames in os.walk(abs_path):
    for filename in filenames:
      if os.path.splitext(filename)[1] != '.h':
        continue
      copy_source_file(os.path.join(dirpath, filename), relative_to=relative_to, destination=destination)


def copy_source_file(absolute_path, relative_to, destination):
  relative_path = os.path.relpath(absolute_path, start=relative_to)
  final_path = os.path.join(destination, relative_path)
  mkdir_p(os.path.dirname(final_path))
  shutil.copy2(absolute_path, final_path)


def copy_dir(relative_path, relative_to, destination):
  abs_path = os.path.join(relative_to, relative_path)
  for dirpath, dirnames, filenames in os.walk(abs_path):
    for filename in filenames:
      copy_source_file(os.path.join(dirpath, filename), relative_to=relative_to, destination=destination)


def add_gdb_index_section(gdb, objcopy, symfile, dirname, env):
  subprocess.check_call([gdb, '-batch',
                         '-ex', 'file {0}'.format(symfile),
                         '-ex', 'save gdb-index .'], cwd=dirname, env=env)
  index_file = symfile + '.gdb-index'
  subprocess.check_call([objcopy, '--add-section',
                         '.gdb_index={0}'.format(index_file),
                         '--set-section-flags', '.gdb_index=readonly',
                         symfile, symfile], cwd=dirname, env=env)
  os.unlink(os.path.join(dirname, index_file))


def create_debug_file(gdb, objcopy, binfile, symfile, dirname, env):
  subprocess.check_call([objcopy, '--only-keep-debug', binfile, symfile],
                        cwd=dirname, env=env)
  # add gdb_index section to the debug file, which will improve load speed.
  add_gdb_index_section(gdb, objcopy, symfile, dirname, env)


def link_binary_to_debug_file(objcopy, binfile, symfile, dirname, env):
  subprocess.check_call([objcopy, '--add-gnu-debuglink={0}'.format(symfile),
                         binfile], cwd=dirname, env=env)


def run_strip(target_arch, filename, create_debug_archive):
  # Static libraries are not stripped because it would remove
  # all the symbols in it.
  if filename.endswith('.a'):
    return

  if TARGET_PLATFORM == 'linux':
    strip_flags = []
  else:
    strip_flags = ['-x', '-S']

  env = os.environ.copy()
  if target_arch == 'arm64':
    binutils_dir = os.path.join(VENDOR_DIR, 'binutils-aarch64')
    env['LD_LIBRARY_PATH'] = binutils_dir + '/usr/x86_64-linux-gnu/aarch64-linux-gnu/lib'
    env['PATH'] = os.pathsep.join([binutils_dir + '/usr/bin', env['PATH']])

  if target_arch == 'arm' and filename.endswith(('.so', 'chromedriver')):
    strip = 'arm-linux-gnueabihf-strip'
    objcopy = 'arm-linux-gnueabihf-objcopy'
    gdb = 'arm-linux-gnueabihf-gdb'
  elif target_arch == 'arm64' and filename.endswith(('.so', 'chromedriver')):
    strip = 'aarch64-linux-gnu-strip'
    objcopy = 'aarch64-linux-gnu--objcopy'
    gdb = 'aarch64-linux-gnu-gdb'
  else:
    strip = 'strip'
    objcopy = 'objcopy'
    gdb = 'gdb'
  dirname = os.path.dirname(filename)
  symfile = '{0}.debug'.format(os.path.basename(filename))
  create_debug_archive = (create_debug_archive
                          # don't create debug file for libffmpeg as a
                          # different version will be bundled.
                          and not symfile.startswith('libffmpeg'))
  if create_debug_archive:
    create_debug_file(gdb, objcopy, filename, symfile, dirname, env)
  subprocess.check_call([strip] + strip_flags + [filename], env=env)
  if create_debug_archive:
    link_binary_to_debug_file(objcopy, filename, symfile, dirname, env)


def run_ar_combine(filename, target_dir):
  target = os.path.join(target_dir, os.path.basename(filename))
  ar_combine = os.path.join(SOURCE_ROOT, 'tools', 'linux', 'ar-combine.sh')
  subprocess.check_call([ar_combine, '-o', target, filename])


def generate_licenses():
  file_template = os.path.join(SOURCE_ROOT, 'resources', 'about_credits.tmpl')
  entry_template = os.path.join(SOURCE_ROOT, 'resources',
                                'about_credits_entry.tmpl')
  licenses_py = os.path.join(SOURCE_ROOT, 'tools', 'licenses.py')
  target = os.path.join(MAIN_DIR, 'LICENSES.chromium.html')
  subprocess.check_call([sys.executable, licenses_py, 'credits', target,
                         '--file-template', file_template,
                         '--entry-template', entry_template])


def create_zip(create_debug_archive):
  print 'Zipping shared_library builds...'
  p = os.path.join(SOURCE_ROOT, 'libchromiumcontent.zip')
  make_zip(MAIN_DIR, ['src', 'ffmpeg', 'shared_library'], ['LICENSES.chromium.html'], p)
  if create_debug_archive and TARGET_PLATFORM in ['linux', 'darwin']:
    print 'Zipping shared library debug files...'
    p = os.path.join(SOURCE_ROOT, 'libchromiumcontent-dbg.zip')
    make_zip(MAIN_DIR, ['.debug'], [], p)
  print 'Zipping static_library builds...'
  p = os.path.join(SOURCE_ROOT, 'libchromiumcontent-static.zip')
  make_zip(MAIN_DIR, ['static_library'], [], p)


def make_zip(src, dirs, files, target):
  safe_unlink(target)
  with scoped_cwd(src):
    zip_file = zipfile.ZipFile(target, 'w', zipfile.ZIP_DEFLATED,
                               allowZip64=True)
    for dirname in dirs:
      for root, _, filenames in os.walk(dirname):
        for f in filenames:
          zip_file.write(os.path.join(root, f))
    for f in files:
      zip_file.write(f)
    zip_file.close();


def mkdir_p(path):
  try:
    os.makedirs(path)
  except OSError as e:
    if e.errno != errno.EEXIST:
      raise


def rm_rf(path):
  try:
    shutil.rmtree(path)
  except OSError as e:
    if e.errno != errno.ENOENT:
      raise


def safe_unlink(path):
  try:
    os.unlink(path)
  except OSError as e:
    if e.errno != errno.ENOENT:
      raise


def is_newer(destination, source):
  return os.path.exists(destination) and \
    os.path.getmtime(destination) > os.path.getmtime(source)


@contextlib.contextmanager
def scoped_cwd(path):
  cwd = os.getcwd()
  os.chdir(path)
  try:
    yield
  finally:
    os.chdir(cwd)


if __name__ == '__main__':
  sys.exit(main())
